﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using tiDE.SourceInsight;

namespace tiDE
{
    public partial class SpriteEdit : DockContent
    {
        int numLevels = 2;
        Bitmap image;
        int width = 8, height = 8;
        int selectedToolIndex = 0;
        double zoom = 50;
        CustomPanel panel1;
        ISourceInsightProvider insightProvider;

        public SpriteEdit()
        {
            InitializeComponent();
            comboBox1.SelectedIndex = 0;
            panel1 = new CustomPanel();
            panel1.Dock = DockStyle.Fill;
            panel1.Paint += new PaintEventHandler(panel1_Paint);
            panel1.MouseDown += new MouseEventHandler(panel1_MouseDown);
            panel1.MouseMove += new MouseEventHandler(panel1_MouseMove);
            panel1.MouseUp += new MouseEventHandler(panel1_MouseUp);
            splitContainer1.Panel2.Controls.Add(panel1);
            image = new Bitmap(width, height);
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    image.SetPixel(x, y, Color.White);
                }
            }

            if (tiDEWindow.ThisInstance.CurrentSolution != null)
            {
                string language = tiDEWindow.ThisInstance.CurrentSolution.Language;
                insightProvider = InsightManager.GetProviderForExtension(language);
            }
        }

        void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            IsLeftMouseDown = false;
            IsRightMouseDown = false;
        }

        void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsLeftMouseDown || IsRightMouseDown)
            {
                Point drawnPoint = MouseToCoordinates(e.Location);
                if (PreviousCoordinates != drawnPoint)
                {
                    if (drawnPoint.X < width && drawnPoint.Y < height)
                    {
                        switch (selectedToolIndex)
                        {
                            case 0:
                                ApplyPencil(drawnPoint.X, drawnPoint.Y,
                                    IsLeftMouseDown ? pictureBox2.BackColor : pictureBox1.BackColor);
                                break;
                            case 1:
                                ApplyBrush(drawnPoint.X, drawnPoint.Y,
                                    IsLeftMouseDown ? pictureBox2.BackColor : pictureBox1.BackColor);
                                break;
                            case 2:
                                ApplyFill(drawnPoint.X, drawnPoint.Y,
                                    IsLeftMouseDown ? pictureBox2.BackColor : pictureBox1.BackColor,
                                    image.GetPixel(drawnPoint.X, drawnPoint.Y));
                                break;
                        }
                        panel1.Invalidate();
                        if (insightProvider != null)
                        {
                            textBox1.TextChanged -= textBox1_TextChanged;
                            textBox1.Text = insightProvider.BitmapToSource(image, numLevels);
                            textBox1.TextChanged += textBox1_TextChanged;
                        }
                    }
                    PreviousCoordinates = drawnPoint;
                }
            }
        }

        void ApplyFill(int x, int y, Color color, Color startingColor)
        {
            if (x >= width || x < 0 ||
                y >= height || y < 0)
                    return;
            if (image.GetPixel(x, y) != startingColor)
                return;
            image.SetPixel(x, y, color);
            ApplyFill(x - 1, y, color, startingColor);
            ApplyFill(x + 1, y, color, startingColor);
            ApplyFill(x, y - 1, color, startingColor);
            ApplyFill(x, y + 1, color, startingColor);
        }

        void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
                IsLeftMouseDown = true;
            else if (e.Button == System.Windows.Forms.MouseButtons.Right)
                IsRightMouseDown = true;
            if (IsLeftMouseDown || IsRightMouseDown)
            {
                Point drawnPoint = MouseToCoordinates(e.Location);
                if (drawnPoint.X < width && drawnPoint.Y < height)
                {
                    switch (selectedToolIndex)
                    {
                        case 0:
                            ApplyPencil(drawnPoint.X, drawnPoint.Y,
                                IsLeftMouseDown ? pictureBox2.BackColor : pictureBox1.BackColor);
                            break;
                        case 1:
                            ApplyBrush(drawnPoint.X, drawnPoint.Y,
                                IsLeftMouseDown ? pictureBox2.BackColor : pictureBox1.BackColor);
                            break;
                        case 2:
                            ApplyFill(drawnPoint.X, drawnPoint.Y,
                                    IsLeftMouseDown ? pictureBox2.BackColor : pictureBox1.BackColor,
                                    image.GetPixel(drawnPoint.X, drawnPoint.Y));
                            break;
                    }
                    panel1.Invalidate();
                    if (insightProvider != null)
                    {
                        textBox1.TextChanged -= textBox1_TextChanged;
                        textBox1.Text = insightProvider.BitmapToSource(image, numLevels);
                        textBox1.TextChanged += textBox1_TextChanged;
                    }
                }
                PreviousCoordinates = drawnPoint;
            }
        }

        void ApplyBrush(int x, int y, Color color)
        {
            ApplyPencil(x, y, color);
            if (x != 0)
                ApplyPencil(x - 1, y, color);
            if (y != 0)
                ApplyPencil(x, y - 1, color);
            if (x != width - 1)
                ApplyPencil(x + 1, y, color);
            if (y != height - 1)
                ApplyPencil(x, y + 1, color);
        }

        void ApplyPencil(int x, int y, Color color)
        {
            if (x >= 0 && y >= 0)
                image.SetPixel(x, y, color);
        }

        void panel1_Paint(object sender, PaintEventArgs e)
        {
            int pixelSize = (int)zoom;
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
            e.Graphics.DrawImage(image, new Rectangle(0, 0, pixelSize * width, pixelSize * height));
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    e.Graphics.DrawRectangle(Pens.Red, new Rectangle(
                        x * pixelSize, y * pixelSize, pixelSize, pixelSize));
                }
            }
        }

        private void UpdateGreyLevels()
        {
            flowLayoutPanel1.Controls.Clear();
            double grays = (double)numLevels - 1;
            for (double i = 0; i < grays + 1; i++)
            {
                PictureBox pic = new PictureBox();
                pic.BorderStyle = BorderStyle.FixedSingle;
                pic.Cursor = Cursors.Hand;
                pic.MouseUp += new MouseEventHandler(pic_MouseUp);
                pic.Width = 20;
                pic.Height = 20;
                pic.BackColor = Color.FromArgb(255, (int)(255 * (i / grays)),
                    (int)(255 * (i / grays)), (int)(255 * (i / grays)));
                flowLayoutPanel1.Controls.Add(pic);
            }
        }

        void pic_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
                pictureBox2.BackColor = (sender as PictureBox).BackColor;
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
                pictureBox1.BackColor = (sender as PictureBox).BackColor;
        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            UpdateGreyLevels();
        }

        private void pictureBox4_Click(object sender, EventArgs e)
        {
            pictureBox4.BorderStyle = BorderStyle.None;
            pictureBox5.BorderStyle = BorderStyle.None;
            pictureBox6.BorderStyle = BorderStyle.None;
            (sender as PictureBox).BorderStyle = BorderStyle.FixedSingle;
            if (pictureBox4.BorderStyle == BorderStyle.FixedSingle)
                selectedToolIndex = 0;
            if (pictureBox5.BorderStyle == BorderStyle.FixedSingle)
                selectedToolIndex = 1;
            if (pictureBox6.BorderStyle == BorderStyle.FixedSingle)
                selectedToolIndex = 2;
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            numLevels = int.Parse(comboBox1.SelectedItem.ToString());
            UpdateGreyLevels();
        }

        private void numericUpDown3_ValueChanged(object sender, EventArgs e)
        {
            width = (int)numericUpDown3.Value;
            Bitmap newImage = new Bitmap(width, height);
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x < image.Width && y < image.Height)
                        newImage.SetPixel(x, y, image.GetPixel(x, y));
                    else
                        newImage.SetPixel(x, y, Color.White);
                }
            }
            image = newImage;
            panel1.Invalidate();
        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {
            height = (int)numericUpDown2.Value;
            Bitmap newImage = new Bitmap(width, height);
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if (x < image.Width && y < image.Height)
                        newImage.SetPixel(x, y, image.GetPixel(x, y));
                    else
                        newImage.SetPixel(x, y, Color.White);
                }
            }
            image = newImage;
            panel1.Invalidate();
        }

        private void splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
        {
        }

        bool IsLeftMouseDown = false, IsRightMouseDown = false;
        Point PreviousCoordinates;

        private void splitContainer1_MouseDown(object sender, MouseEventArgs e)
        {

        }

        private void splitContainer1_MouseMove(object sender, MouseEventArgs e)
        {

        }

        private void splitContainer1_MouseUp(object sender, MouseEventArgs e)
        {

        }

        private Point MouseToCoordinates(Point Mouse)
        {
            int pixelSize = (int)zoom;
            return new Point(Mouse.X / pixelSize, Mouse.Y / pixelSize);
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            try
            {
                image = insightProvider.SourceToBitmap(textBox1.Text, numLevels, width, height);
                panel1.Invalidate();
            }
            catch
            {
                
            }
        }
    }
}
